#pragma once 

#include "EventLoop.h"
#include "InetAddress.h"
#include "Event.h"
#include<memory>
#include <unordered_map>

#include <atomic>


namespace tmms
{
    namespace network
    {
        enum {
            KNormalContext = 0 ,
            KRtmpContext,
            KHttpContex,
            KUserContext,
            KFlvContext,
        };
        struct BufferNode
        {
            BufferNode(void *buf,size_t s):addr(buf),size(s){}
            void *addr{nullptr}; //数据
            size_t size{0};//数据大小
        };

        using BufferNodePtr = std::shared_ptr<BufferNode>;

        using ContextPtr = std::shared_ptr<void>;
        class Connection;
        using ConnectionPtr = std::shared_ptr<Connection>;
        using ActiveCallback = std::function<void(const ConnectionPtr &)>;

        class Connection:public Event
        {
        public:
            Connection(EventLoop * loop,int fd, const InetAddress &localAddr,const InetAddress &peerAddr);

            virtual ~Connection()=default; 

            void SetLocalAddr(const InetAddress &local);
            void SetPeerlAddr(const InetAddress &peer);
            InetAddress& GetLocallAddr()  ;
            InetAddress& GetPeerlAddr() ;

            void SetContext(int type,const std::shared_ptr<void> &context);
            void SetContext(int type,std::shared_ptr<void> &&context); // 为了效率，定义一个移动语义的参数

            /*​​含有模板的成员函数通常需要将定义（实现）
            放在头文件（.h或.hpp）中​​，
            而非单独放在.cpp文件中
            。这是由模板的编译机制决定的*/
            template <typename T> std::shared_ptr<T> GetContext(int type) const
            {
                auto iter = contexts_.find(type);
                if(iter != contexts_.end())
                {
                    return std::dynamic_pointer_cast<T>(iter->second);
                }
                return std::shared_ptr<T>();//返回空
            }
            
            void ClearContext(int type);
            void ClearContext();

            void SetActiveCallback(const ActiveCallback &cb);
            void SetActiveCallback(ActiveCallback &&cb);//有时候是lamda表达式
            void Active();
            void Deactive();


            virtual void ForceClose() = 0;// tcp和udp的关闭是不一样的，所以要子类实现


        private:
            std::unordered_map<int,ContextPtr> contexts_;
            ActiveCallback active_cb_;
            std::atomic<bool> active_{false}; //因为激活和非激活的是在不同的线程的，所以使用原子变量 
        protected:
            InetAddress local_addr_;
            InetAddress peer_addr_;
        };

    }
}